import {
  computed,
  defineComponent,
  getCurrentInstance,
  nextTick,
  onMounted,
  onUnmounted,
  reactive,
  ref,
  watch,
} from 'vue';

import useMappingProps from 't/common/hooks/useMappingProps';
import {
  commonProps,
  pickOwnForBasicComponent,
  usePropsTwoWayValues,
} from 't/common/utils';

import { useProps, useOptsProps } from './props';

import './index.scss';

import _, { forIn, orderBy } from 'lodash';
import { useI18n } from 'vue-i18n';

import { DxButton } from 'devextreme-vue/button';
import {
  DxTreeList,
  DxColumn,
  DxSelection,
  DxFilterRow,
  DxLoadPanel,
  DxPaging,
  DxScrolling,
  DxSorting,
} from 'devextreme-vue/tree-list';
import TMenu from 't/basic/menu';
import TList from 't/basic/list';
import TItem from 't/basic/item';
import TItemSection from 't/basic/item-section';
import treeConvert from './tree-convert';

import QInnerLoading from '@teld/q-components/InnerLoading';

import NoDataPlaceholder from 't/bussiness/data-grid/components/no-data-placeholder.vue';

import CmdColumn from 't/bussiness/data-grid/column/CmdColumn';
import EnumColumn from 't/bussiness/data-grid/column/EnumColumn';
import LinkColumn from 't/bussiness/data-grid/column/LinkColumn';
import HintCol from 't/bussiness/data-grid/hintCol';
import FormatFunctions from 't/bussiness/data-grid/lib/FormatFunctions';
import { formatNumber, formatDate } from 'devextreme/localization';

import zhMessages from 'devextreme/localization/messages/zh.json';
import enMessages from 'devextreme/localization/messages/en.json';
import ptMessages from 'devextreme/localization/messages/pt.json';
import ruMessages from 'devextreme/localization/messages/ru.json';
import kkMessages from './lang/kk.json'; /** 哈萨克斯坦 */
import { locale, loadMessages } from 'devextreme/localization';

import {
  date,
  debounce,
  dom,
  setCssVar,
  useQuasar,
  scroll,
} from '@teld/q-components';

const SelectionMode = {
  none: 'none',
  single: 'single',
  multiple: 'multiple',
};

const omitProps = ['dataSource'];
const propsTreeList = _.omit(DxTreeList.props, omitProps);

const C = {
  PID: '_P_I_D_',
  PID_FLATTEN: 'FLATTEN',
  Has_Child_Code: '_hasChildCode_',
};

export default defineComponent({
  name: 'TTreeList',
  props: {
    ...propsTreeList,
    ...commonProps,
    selectMode: {
      type: String,
      default() {
        return SelectionMode.none;
      },
    },
    enableUnSelect: {
      type: Boolean,
      default() {
        return false;
      },
    },
    recursiveSelection: {
      type: Boolean,
      default() {
        return false;
      },
    },
    allowSelectAll: {
      type: Boolean,
      default() {
        return true;
      },
    },
    hideHeader: {
      type: Boolean,
      default() {
        return false;
      },
    },
    rowHeight: {
      type: String,
      default() {
        return '48px';
      },
    },
    loading: {
      type: Boolean,
      default() {
        return false;
      },
    },
    ...useProps,
    ...useOptsProps,
    dataStructure: {
      type: String,
      default() {
        return 'plain';
      },
    },
    levelKeyExpr: {
      type: String,
      default() {
        return 'Code';
      },
    },
    parentIdExpr: {
      type: String,
      default() {
        return 'PID';
      },
    },
    levelParentIdExpr: {
      type: String,
      default() {
        return '_PLEVEL_';
      },
    },
    lazyItems: {
      type: Boolean,
      default() {
        return false;
      },
    },
    hasItemsExpr: {
      type: String,
      default() {
        return 'IsLeaf';
      },
    },
    leafValue: {
      type: [String, Boolean],
      default() {
        return 'true';
      },
    },
    hasItemsExprValue: {
      type: String,
      default() {
        return '';
      },
    },
    isClassiFicationSteps: {
      type: Boolean,
      default() {
        return true;
      },
    },
    classiFicationStep: {
      type: String,
      default() {
        return '3';
      },
    },
    classiFicationStepRule: {
      type: String,
      default() {
        return '2-3-3';
      },
    },
    noDataText: {
      type: String,
      default() {
        return '暂无数据';
      },
    },
    columnAutoWidth: {
      type: Boolean,
      default() {
        return false;
      },
    },
  },
  emits: [
    'lazyLoad',
    'request',
    'selectionChanged',
    'cellPrepared',
    'rowExpanded',
    'rowCollapsed',
    'cmdColClick',
    'beforeContextMenuShow',
    'contextMenuClick',
    'dataSourceLoaded',
  ],

  setup(props, { attrs, emit, expose, slots }) {
    // const vm = getCurrentInstance()
    const $q = useQuasar();
    const { t } = useI18n({ useScope: 'global' });

    if (window.DevExpress) return;

    if (window.readCookie) {
      if (readCookie('teld_locale') == 'en-US') {
        loadMessages(enMessages);
      } else if (readCookie('teld_locale') == 'pt-BR') {
        loadMessages(ptMessages);
      } else if (readCookie('teld_locale') == 'kk-KZ') {
        loadMessages(kkMessages);
      } else {
        loadMessages(zhMessages);
        loadMessages({
          /** 参考 {解释型组件}src\render\devextreme\localization\messages\zh.json  */
          'zh': {
            'dxDataGrid-trueText': '是',
            'dxDataGrid-falseText': '否',
          },
          'zh-tw': {
            'dxDataGrid-trueText': '是',
            'dxDataGrid-falseText': '否',
          },
        });
      }

      //** dev组件对接 teld_locale 国际化 */
      let teldLocale = readCookie('teld_locale');
      if (teldLocale) {
        switch (teldLocale) {
          case 'zh-TW':
          case 'zh-HK':
            locale('zh-tw');
            break;
          case 'kk-KZ':
            locale('kk-KZ');
            break;
          default:
            let l = teldLocale.split('-')[0];
            locale(l);
        }
      } else {
        locale(navigator.language);
      }
    }

    const [mappingProps, mappingExpose] = useMappingProps(props, {});

    const propsSelection = computed(() => {
      return {
        mode: mappingProps.selectMode,
        recursive: mappingProps.recursiveSelection,
        allowSelectAll: mappingProps.allowSelectAll,
      };
    });
    const readerSelection = () => {
      return (
        <DxSelection
          {...propsSelection.value}
          // allowSelectAll={false}
        ></DxSelection>
      );
    };

    let observer;

    const treeListWidth = ref(0);
    onMounted(() => {
      // 创建一个观察者对象
      observer = new MutationObserver((mutationsList, observer) => {
        for (const mutation of mutationsList) {
          if (
            mutation.type === 'attributes' &&
            mutation.attributeName === 'style'
          ) {
            const maxWidth = getComputedStyle(mutation.target).maxWidth;
            if ('none' != maxWidth) treeListWidth.value = maxWidth;
            // console.log(`Element width changed to: ${maxWidth}`);
            // 在这里处理宽度变化的逻辑
          }
        }
      });
      // 使用配置文件调用observe方法
      const config = {
        attributes: true,
        childList: true,
        subtree: true,
        attributeFilter: ['style'],
      };
      // 传入目标节点和观察选项开始观察
      // const $el = refComponent.value.$el;
      const $el = refTreeList.value._$element[0];
      props.isDev !== true && observer.observe($el, config);
      treeListWidth.value = getComputedStyle($el)?.width;
    });

    onUnmounted(() => {
      observer.disconnect?.();
    });

    const mappingColumns = computed(() => {
      let mappingColumns = mappingProps?.optColumns || [];
      return publicMethod.optColumns2DxColumns(mappingColumns);
    });

    const computedColumns = computed(() => {
      let columns = mappingProps?.columns || mappingColumns.value || [];
      return columns;
    });

    function dynamicHeaderTemplate(col, i) {
      let returnValue = '';
      if (col.hintConf && col.hintConf.enable) {
        returnValue = 'headerTemplate';
      }
      return returnValue;
    }

    function dynamicCellTemplate(col, i) {
      let returnValue = '';
      let hasLinkFormat = false == _.isEmpty(col.linkFormat);
      let hasEnumDisp =
        col.enumDisp &&
        col.enumDisp.enumRanges &&
        col.enumDisp.enumRanges.length > 0;
      let hasFormat = col.dataFormat && col.dataFormat.FormatType;
      let isDateCol =
        col &&
        (col.dataType == 'date' || col.dataType == 'datetime') &&
        col.format;
      if (hasLinkFormat && hasEnumDisp) {
        returnValue = 'link-enum-cell-template';
      } else if (hasLinkFormat && (hasFormat || isDateCol)) {
        returnValue = 'link-format-cell-template';
      } else if (hasLinkFormat) {
        returnValue = 'link-cell-template';
      } else if (hasEnumDisp) {
        returnValue = 'enum-cell-template';
      }
      return _.camelCase(returnValue);
    }

    const calculateFilterExpression = col => {
      let extendCol = {};
      if (col) {
        switch (col?.dataFormat?.FormatType) {
          case 'Discount':
            extendCol.calculateFilterExpression = (
              filterValue,
              selectedFilterOperation,
              target,
            ) =>
              publicMethod.calculateFilterExpressionDiscount(
                filterValue,
                selectedFilterOperation,
                target,
                col,
              );
            break;
          case 'Percent':
            extendCol.calculateFilterExpression = (
              filterValue,
              selectedFilterOperation,
              target,
            ) =>
              publicMethod.calculateFilterExpressionPercent(
                filterValue,
                selectedFilterOperation,
                target,
                col,
              );
            break;
        }

        if (col.enumDisp && _.size(col.enumDisp.enumRanges) > 0) {
          if (props.isDev !== true) {
            extendCol.dataType = 'string';
            extendCol.calculateFilterExpression = (
              value,
              selectedFilterOperations,
              target,
            ) =>
              publicMethod.calculateFilterExpressionCol(
                value,
                selectedFilterOperations,
                target,
                col,
              );
          }
        }
      }

      return extendCol;
    };

    const colCalculateProps = col => {
      let extendCol = {};

      if (col) {
        if (
          col.dataFormat &&
          col.dataFormat.FormatType &&
          props.isDev !== true
        ) {
          extendCol.calculateDisplayValue = rowData =>
            publicMethod.calculateDisplayValue(rowData, col);
          // extendCol.calculateSortValue = rowData =>
          //   publicMethod.calculateSortValue(rowData, col);

          if (col.dataFormat.FormatType == 'Discount') {
            extendCol.sortingMethod = (value1, value2) => {
              if (!value1 && value2) return 1;
              if (!value1 && !value2) return 0;
              if (value1 && !value2) return -1;
              // Determines whether two strings are equivalent in the current locale
              return value2 - value1;
            };
          }
        }
      }
      return extendCol;
    };

    const readerDevMockColumns = () => {
      if (computedColumns.value.length == 0 && props.isDev)
        return ['字段1', '字段2'].map(col => (
          <DxColumn caption={col}></DxColumn>
        ));
      return [];
    };
    // const vnode = <div id={dynamicId}>hello, {userName}</div>;
    const readerColumns = () => {
      const dxColumn = computedColumns.value.map((col, i) => {
        let extendCol = {};

        return (
          <DxColumn
            {...col}
            headerCellTemplate={
              col.optCol && dynamicHeaderTemplate(col.optCol, i)
            }
            cellTemplate={col.optCol && dynamicCellTemplate(col.optCol, i)}
            {...colCalculateProps(col.optCol)}
            {...(mappingProps.showAutoFilterRow &&
              calculateFilterExpression(col.optCol))}
            allowSorting={false}
          ></DxColumn>
        );
      });
      return dxColumn.concat(mappingProps.enableCmdCol && readerCmdCol());
    };

    const readerCmdCol = () => {
      const { columnConf, commands } = mappingProps.optCmdColConfig;
      let stickyCmdColumn;
      if (commands?.length > 0) {
        const width = columnConf?.width;
        stickyCmdColumn = (
          <DxColumn
            alignment='center'
            allowResizing={false}
            allowSearch={false}
            allowSorting={false}
            fixed={true}
            fixedPosition='right'
            caption={t(columnConf?.ValueInfo_caption, columnConf?.caption)}
            dataField=''
            width={width}
            cellTemplate='cellSlotCmdColumn'
          ></DxColumn>
        );
      }
      return stickyCmdColumn;
    };

    const propsFilterRow = computed(() => {
      return {
        visible: mappingProps.showAutoFilterRow,
      };
    });

    const readerFilterRow = () => {
      return <DxFilterRow {...propsFilterRow.value}></DxFilterRow>;
    };

    const propsTreeListHeight = computed(() => {
      return {
        height: mappingProps.height || 500,
      };
    });

    const refTreeList = ref(null);

    const propColumnHidingEnabled = computed(() => {
      return mappingProps.columnHidingEnabled;
    });
    const IsLevelStructure = computed(() => {
      return (mappingProps.dataStructure || 'plain') == 'plain_level';
    });

    const computedLevelParentIdExpr = computed(() => {
      return _.get(mappingProps, 'levelParentIdExpr', '_PLEVEL_');
    });

    const computedDataStructure = computed(() => {
      let isPlain_level = IsLevelStructure.value;
      let rootValue = findRootValue.value || mappingProps.rootValue || '';
      if (isPlain_level) rootValue = '';
      return {
        dataStructure: 'plain',
        keyExpr: isPlain_level
          ? mappingProps.levelKeyExpr
          : mappingProps.keyExpr || 'ID',
        parentIdExpr: isPlain_level
          ? computedLevelParentIdExpr.value
          : mappingProps.parentIdExpr,
        rootValue: hasOutsideFilter.value ? C.PID_FLATTEN : rootValue,
      };
    });

    watch(
      () => mappingProps.rootValue,
      val => {
        if (val == 'auto') {
          setFindRootValue(dataSource.value);
        } else {
          findRootValue.value = val;
        }
      },
    );

    const enumDispArray = computed(() => {
      return _.filter(
        mappingProps.optColumns,
        item => item.enumDisp && item.enumDisp.valMapping,
      );
    });

    const findRootValue = ref(mappingProps.rootValue || '');
    const getFindRootValue = ds => {
      ds = ds || dataSource.value;
      let findRootNode = _.first(
        _.minBy(
          _.values(_.groupBy(ds, computedDataStructure.value.parentIdExpr)),
          o => o.length,
        ),
      );
      return findRootNode?.[computedDataStructure.value.parentIdExpr];
    };
    const setFindRootValue = ds => {
      if (false === IsLevelStructure.value) {
        findRootValue.value = getFindRootValue(ds);
      }
    };
    const outsideFilter = ref({});
    const hasOutsideFilter = computed(() => {
      return Object.keys(outsideFilter.value).length > 0;
    });
    function warpEnumDisp(val) {
      if (enumDispArray.value.length > 0) {
        _.each(val, item => {
          _.each(enumDispArray.value, colConf => {
            if (_.has(item, colConf.dataField)) {
              let enumDisp = colConf.enumDisp;
              let originalVal = item[colConf.dataField];

              let confByVal = _.find(enumDisp.enumRanges, enumRangeItem => {
                return enumRangeItem.val === `${originalVal}`;
              });

              let returnValue = originalVal;

              if (confByVal) {
                returnValue = enumDisp.valMapping
                  ? confByVal.text || originalVal
                  : originalVal;
              }
              item[`${colConf.dataField}_$mapping`] = returnValue;
            }
          });
        });
      }

      _.each(val, item => {
        if (hasOutsideFilter.value) {
          item[C.Has_Child_Code] = false;
          item[C.PID] = C.PID_FLATTEN;
        } else {
          item[C.PID] = item[computedDataStructure.value.parentIdExpr];
        }
      });
      return val;
    }
    let initDataSource = mappingProps?.rows || [];
    if (IsLevelStructure.value) {
      initDataSource = treeConvert.convertLevel2ParentId(
        mappingProps?.rows || [],
        mappingProps.levelKeyExpr,
        computedLevelParentIdExpr.value,
      );
    }
    const dataSource = ref(warpEnumDisp(initDataSource));
    watch(
      () => mappingProps?.rows,
      (newVal, oldVal) => {
        debugger;
        let mapNodes = _.map(newVal, node => {
          const isLeft = !(
            `${node[mappingProps.hasItemsExpr]}` ==
            `${mappingProps.leafValue == 'custom' ? mappingProps.hasItemsExprValue : mappingProps.leafValue}`
          );
          return { ...node, [C.Has_Child_Code]: isLeft };
        });
        if (IsLevelStructure.value) {
          mapNodes = treeConvert.convertLevel2ParentId(
            mapNodes,
            mappingProps.levelKeyExpr,
            computedLevelParentIdExpr.value,
          );
        }
        dataSource.value = warpEnumDisp(mapNodes);
      },
      // { immediate: true },
    );
    const expandedRowKeys = ref([]);
    const lazyCode = ref(IsLevelStructure.value ? '' : mappingProps.rootValue);
    function onRowExpanding(e) {
      let { component, element, key } = e;
      if (mappingProps.lazyItems) {
        let node = component.getNodeByKey(key);
        if (node && _.size(node.children) > 0) {
          return;
        }
        lazyCode.value = key;
        emit('lazyLoad', e);
      }
    }
    function onRowExpanded(e) {
      let { component, element, key } = e;
      let node = component.getNodeByKey(key);
      let isLoadedChildren = _.size(node.children) > 0;
      emit('rowExpanded', { ...e, isLoadedChildren });
    }

    function onRowCollapsed(e) {
      emit('rowCollapsed', e);
    }

    function onSelectionChanged(e) {
      let { selectedRowsData } = e;
      if (mappingProps.readOnly) {
        return;
      }
      publicMethod.selectedRows.value = publicMethod.getSelectedRowsDataAll();
      emit('selectionChanged', e);
    }
    function onCellClick({ row, rowType }) {
      if (
        rowType == 'data' &&
        row &&
        row.isSelected &&
        mappingProps.selectMode == 'single' &&
        mappingProps.enableUnSelect
      ) {
        // setTimeout(() => {

        // });
        nextTick(() => {
          publicMethod.clearSelection();
        });
      }
    }
    function onCellPrepared(e) {
      publicMethod.cellPreparedInfo.value = e;
      emit('cellPrepared', e);
    }

    const GetFasLazyCode = obj => {
      if (mappingProps.lazyItems && false === hasOutsideFilter.value) {
        let returnValue = { ...obj };
        returnValue[lazyCodeField.value] = GetLazyCode();
        return returnValue;
      } else {
        return { ...obj };
      }
    };
    const GetLazyCode = () => {
      if (IsLevelStructure.value) {
        return calcLazyLevelCode();
      } else {
        if ('auto' === lazyCode.value) {
          return '';
        }
        return lazyCode.value;
      }
    };
    const calcLazyLevelCode = () => {
      let nextLevel = lazyCode.value;
      let {
        isClassiFicationSteps = false,
        classiFicationStep = 3,
        classiFicationStepRule = '2-3',
      } = mappingProps;

      let levelLen = 0;
      if (isClassiFicationSteps) {
        levelLen = +classiFicationStep;
      } else {
        let step = 0;
        let stepRuleArray = `0-${classiFicationStepRule}`.split('-');
        let stepMapping = _.transform(
          stepRuleArray,
          (result, value, index) => {
            result[(step += +value)] =
              +stepRuleArray[
                index == stepRuleArray.length - 1 ? index : index + 1
              ];
          },
          {},
        );

        levelLen =
          stepMapping[nextLevel.length] ||
          stepMapping[_.max(_.keys(stepMapping))];
      }
      return `${nextLevel}${_.repeat('_', levelLen)}`;
    };
    const propsTreeList = computed(() => {
      const propsKey = [
        'autoExpandAll',
        'columnAutoWidth',
        'columnMinWidth',
        'allowColumnResizing',
        'columnResizingMode',
        // 'showColumnHeaders',
        // 'keyExpr',
        // 'parentIdExpr',
      ];
      let pickProps = _.pick(mappingProps, propsKey);
      pickProps = _.pickBy(pickProps, (v, k) => {
        return false === _.isUndefined(v);
      });

      return {
        noDataText: '',
        columnMinWidth: 50,
        showBorders: false,
        showRowLines: true,
        hoverStateEnabled: true,
        rowAlternationEnabled: false,

        // [mappingProps.hasItemsExpr && 'hasItemsExpr']: C.Has_Child_Code, //mappingProps.hasItemsExpr,
        hasItemsExpr:
          mappingProps.lazyItems && mappingProps.hasItemsExpr
            ? C.Has_Child_Code
            : '',
        autoExpandAll: mappingProps.autoExpandAll,
        columnAutoWidth: mappingProps.columnAutoWidth,
        allowColumnResizing: _.get(mappingProps, 'allowColumnResizing', true),
        columnResizingMode: _.get(mappingProps, 'columnResizingMode', 'widget'),
        columnHidingEnabled: propColumnHidingEnabled.value,

        ...pickProps,
        ...propsTreeListHeight.value,
        ...computedDataStructure.value,
        showColumnHeaders: !mappingProps.hideHeader,
        parentIdExpr: C.PID,
      };
    });

    const refComponent = ref();
    const refH = ref(0);
    const refreshHeight = () => {
      refH.value++;
    };
    const h = computed(() => {
      // const {
      //   getScrollTarget,
      //   getVerticalScrollPosition,
      //   setVerticalScrollPosition,
      // } = scroll;
      // let scrollTargetDomElement = getScrollTarget(window.body);
      // let os = getVerticalScrollPosition(scrollTargetDomElement);
      // console.log(os);
      let top = refComponent.value?.$el
        ? dom.offset(refComponent.value?.$el).top
        : 0;

      if (props.isDev) {
        let designPage = document.querySelector('#app > div.design-page');
        if (designPage && designPage.scrollTop) {
          top += designPage.scrollTop;
        }
      } else {
        if (document.scrollingElement.scrollTop > 0) {
          top += document.scrollingElement.scrollTop;
        }
      }

      const simplePagingOffset = mappingProps.simplePaging ? 50 : 0;

      return (
        $q.screen.height - top + (refH.value - refH.value) - simplePagingOffset
      );
    });
    const height = computed(() => {
      let isAuto =
        mappingProps.fillMode == 'auto' ||
        ['auto', 'fill'].includes(
          (mappingProps.height || '').trim().toLowerCase(),
        );
      let mb = mappingProps.fillMarginBottom || '0px';
      let hValue = h.value <= 0 ? mappingProps.height || undefined : h.value;
      return isAuto
        ? `calc(${hValue - parseInt(mb)}px)`
        : mappingProps.height || undefined;
    });

    function cellTemplateData2CellParam(data) {
      let cellParam = {
        value: data.value,
        row: data.data,
        col: {
          field: data.column.dataField,
          optCol: data.column.optCol,
        },
        rowIndex: data.rowIndex,
      };
      return cellParam;
    }

    const beforeContextmenu = evt => {
      emit('beforeContextMenuShow', evt);
    };
    const contextMenuList = rowData => {
      return (
        <TMenu
          touch-position
          context-menu
          class={[styles.contextMenu]}
          onBeforeShow={evt => beforeContextmenu(rowData)}
        >
          <TList>
            {Array.isArray(props.menuDataSource)
              ? props.menuDataSource.map(item => {
                  return (
                    <TItem
                      class={[styles.contextMenuItem]}
                      clickable
                      v-close-popup
                      onClick={e => contextMenuClick(e, rowData, item)}
                      disable={item.disabled}
                    >
                      <TItemSection class='q-pr-none'>
                        <div class={[styles.contextMenuItemSection]}>
                          <div class={[styles.icon]} v-show={item.Icon}>
                            <TIcon name={item.Icon} />
                          </div>
                          <div>{item.Name}</div>
                        </div>
                      </TItemSection>
                    </TItem>
                  );
                })
              : ''}
          </TList>
        </TMenu>
      );
    };
    const cellSlotLink = cellParam => {
      return (
        <div>
          {props.menuModel ? contextMenuList(cellParam) : null}
          <LinkColumn
            cellParam={cellParam}
            record={cellParam.row}
            column={cellParam.col.optCol}
            rowIndex={cellParam.rowIndex}
            onColumnLinkFormat={() => {
              if (props.columnLinkFormat) {
                mappingExpose.cellClickInfo = {
                  data: cellParam.row,
                };
                props.columnLinkFormat(cellParam.col.field);
              }
            }}
          />
        </div>
      );
    };

    const cellSlotEnum = cellParam => {
      return (
        <div>
          {props.menuModel ? contextMenuList(cellParam) : null}
          <EnumColumn
            cellParam={cellParam}
            record={cellParam.row}
            column={cellParam.col.optCol}
            rowIndex={cellParam.rowIndex}
            isDev={props.isDev}
            onColumnLinkFormat={() => {
              let linkFormat = cellParam.col?.optCol?.linkFormat;
              if (props.columnLinkFormat && linkFormat) {
                mappingExpose.cellClickInfo = {
                  data: cellParam.row,
                };
                props.columnLinkFormat(cellParam.col.field);
              }
            }}
          />
        </div>
      );
    };

    const setColCmdInfo = (cmd, data) => {
      mappingExpose.colCmdInfo = {
        command: cmd,
        data: data,
      };
    };

    const cellSlotCmd = cellParam => {
      return (
        <CmdColumn
          record={cellParam.row}
          cmdColConfig={cellParam.col.cmdColConfig}
          rowIndex={cellParam.rowIndex}
          colCommandVisible={(cmd, data) => {
            if (props.colCommandVisible && cmd.exprVisible) {
              setColCmdInfo(cmd, cellParam.row);
              return props.colCommandVisible(cmd);
            } else {
              return true;
            }
          }}
          onCmdColClick={cmd => {
            if (props.cmdColClick && cmd.clientScript) {
              setColCmdInfo(cmd, cellParam.row);
              props.cmdColClick(cmd);
            }
          }}
        />
      );
    };

    const readerTreeList = () => {
      return (
        <>
          <DxTreeList
            ref={refComponent}
            style={{
              height: height.value,
              minHeight: '200px',
            }}
            onInitialized={e => {
              refTreeList.value = e.component;
            }}
            v-model:expandedRowKeys={expandedRowKeys.value}
            {...attrs}
            {...propsTreeList.value}
            dataSource={dataSource.value}
            onRowExpanding={onRowExpanding}
            onRowExpanded={onRowExpanded}
            onRowCollapsed={onRowCollapsed}
            onSelectionChanged={onSelectionChanged}
            onCellClick={onCellClick}
            onCellPrepared={onCellPrepared}
          >
            {{
              default() {
                return [
                  slots.default?.(),
                  ...readerDevMockColumns(),
                  ...readerColumns(),
                  readerSelection(),
                  readerFilterRow(),
                  <DxPaging enabled={false} />,
                  <DxScrolling
                    // useNative={false}
                    // columnRenderingMode='standard'
                    preloadEnabled={true}
                    // renderAsync={false} /** 不是true延迟加载会列抖动 */
                  ></DxScrolling>,
                  <DxSorting mode='None'></DxSorting>,
                ];
              },
              headerTemplate({ data }) {
                return (
                  <div style='display: inline-flex;align-items: center; gap: 3px;'>
                    {data.column.caption}
                    <HintCol
                      column={data.column.optCol}
                      isDevEnv={props.isDev}
                    ></HintCol>
                  </div>
                );
              },
              enumCellTemplate({ data }) {
                let cellParam = cellTemplateData2CellParam(data);
                return cellSlotEnum(cellParam);
              },
              linkEnumCellTemplate({ data }) {
                let cellParam = cellTemplateData2CellParam(data);
                return cellSlotEnum(cellParam);
              },
              linkCellTemplate({ data }) {
                let cellParam = cellTemplateData2CellParam(data);
                return cellSlotLink(cellParam);
              },
              linkFormatCellTemplate({ data }) {
                let cellParam = cellTemplateData2CellParam(data);
                return cellSlotLink(cellParam);
              },
              cellSlotCmdColumn({ data }) {
                let cellParam = cellTemplateData2CellParam(data);
                cellParam.col.cmdColConfig = mappingProps.optCmdColConfig;
                return cellSlotCmd(cellParam);
              },
            }}
          </DxTreeList>
        </>
      );
    };

    const propsEmptyCol = ref({
      minWidth: 20,
      width: 20,
      allowResizing: false,
      allowSearch: false,
      allowSorting: false,
      caption: '',
      dataField: '',
      fixed: true,
      fixedPosition: 'right',
      // calculateDisplayValue() {
      //   return '&nbsp;';
      // },
    });
    const readerEmptyCol = () => {
      return (
        'widget' === mappingProps.columnResizingMode && (
          <DxColumn {...propsEmptyCol.value} />
        )
      );
    };

    const lazyCodeField = computed(() => {
      return IsLevelStructure.value
        ? computedDataStructure.value.keyExpr
        : computedDataStructure.value.parentIdExpr;
    });

    const levelCode = computed(() => {
      const fieldKey = lazyCodeField.value;
      let optCol = mappingProps.optColumns?.find(col => {
        return col.dataField == fieldKey;
      });
      return optCol ? `${optCol.tableAlias}.${optCol.originalName}` : fieldKey;
    });

    const setParameterValue = parameters => {
      let outside = {};
      _.each(parameters, (val, key) => {
        if (false === computedSkipParams.value.includes(key)) {
          if (val || false === val) {
            outside[key] = val;
          }
        }
      });
      outsideFilter.value = outside;
    };
    const ignoreParams = ref([]);
    const computedSkipParams = computed(() => {
      debugger;
      return [
        'PageIndex',
        'PageSize',
        'AdvancedFilter',
        'AdvancedSort',
        'FasDynamicFilter',
        'FasDynamicSort',
        ...(ignoreParams.value || []),
      ];
    });
    const publicMethod = {
      setParameterValue,
      getFindRootValue,
      refreshHeight,
      getFilters(filters) {
        return publicMethod.stringifyQuickFilter(filters);
      },
      stringifyQuickFilter(advancedFilter) {
        let filter = publicMethod.getQuickFilter(advancedFilter);
        return filter == null ? null : JSON.stringify(filter);
      },
      getQuickFilter: advancedFilter => {
        // let { Filters, ...quickFilter } = JSON.parse(
        //   JSON.stringify(publicMethod.getQuickFilterStatement()),
        // );

        let Filters = [];
        let quickFilter = {};
        if (mappingProps.lazyItems && false === hasOutsideFilter.value) {
          quickFilter = {
            ElementType: 'Group',
          };
          Filters = [
            {
              ElementType: 'Filter',
              Code: levelCode.value,
              Condition: IsLevelStructure.value ? 'fixedlengthcontains' : '=',
              Value: publicMethod.getLazyCode(),
            },
          ];
        }

        if (advancedFilter) {
          if (typeof advancedFilter === 'string') {
            try {
              advancedFilter = JSON.parse(advancedFilter);
            } catch (error) {
              console.warn('QuickFilter.getQuickFilter', error);
            }
          }
          if (false === quickFilter.hasOwnProperty('ElementType')) {
            /** 当 传入了 过滤条件 但是快速过滤本身没有条件时，直接返回传入的条件 */
            return advancedFilter;
          }

          if (advancedFilter.Filters && advancedFilter.Filters.length > 0) {
            if (Filters) {
              Filters?.push({
                ElementType: 'Relation',
                Relation: 'and',
              });
              Filters?.push(advancedFilter);
            } else {
              Filters = advancedFilter.Filters;
            }
          }
        }
        let returnValue = { ...quickFilter, Filters };
        return returnValue.hasOwnProperty('ElementType') ? returnValue : null;
        // return Filters?.length > 0 ? { ...quickFilter, Filters } : null;
      },
      query() {
        lazyCode.value = IsLevelStructure.value ? '' : mappingProps.rootValue;
        publicMethod.collapsAll();
        emit('request');
      },
      lazyQuery() {
        emit('request');
      },
      refresh() {
        publicMethod.query();
      },
      setIgnoreParams(ignoreParamsValue) {
        if (_.isArray(ignoreParamsValue))
          ignoreParams.value = ignoreParamsValue || [];
      },
      ignoreParams,
      getLazyCode: GetLazyCode,
      lazyCode: computed(() => {
        return GetLazyCode();
      }),
      getFasLazyCode: GetFasLazyCode,
      clearSelection() {
        publicMethod.widgetInstance.value.clearSelection();
      },
      getSelectedRowsData(mode) {
        return publicMethod.widgetInstance.value.getSelectedRowsData(mode);
      },
      getDataFormRows(selectedRowsData) {
        let keyExpr = computedDataStructure.value.keyExpr;
        let keys = _.map(selectedRowsData, computedDataStructure.value.keyExpr);
        return mappingProps.rows.filter(row => {
          return _.includes(keys, row[computedDataStructure.value.keyExpr]);
        });
      },
      getSelectedRowsDataAll(flag) {
        let selectedRows = publicMethod.getSelectedRowsData('all');
        if (flag) {
          return selectedRows;
        }
        return publicMethod.getDataFormRows(selectedRows);
      },
      getSelectedRowsDataExcludeRecursive(flag) {
        let selectedRows = publicMethod.getSelectedRowsData('excludeRecursive');
        if (flag) {
          return selectedRows;
        }
        return publicMethod.getDataFormRows(selectedRows);
      },
      getSelectedRowsDataLeavesOnly(flag) {
        let selectedRows = publicMethod.getSelectedRowsData('leavesOnly');
        if (flag) {
          return selectedRows;
        }
        return publicMethod.getDataFormRows(selectedRows);
      },
      convertLevel2ParentId: treeConvert.convertLevel2ParentId,
      expandAll() {
        if (mappingProps.lazyItems) {
          return;
        }
        expandedRowKeys.value = _.map(
          dataSource.value,
          computedDataStructure.value.keyExpr,
        );
      },
      collapsAll() {
        expandedRowKeys.value = [];
      },
      isExpandAll() {
        return _.size(expandedRowKeys.value) == _.size(dataSource.value);
      },
      widgetInstance: refTreeList,
      expandedRowKeys: expandedRowKeys,
      selectedRows: ref([]),
      isSelectedRow: computed(() => {
        return _.size(publicMethod.selectedRows.value) > 0;
      }),
      selectedRow: computed(() => {
        return _.first(publicMethod.selectedRows.value);
      }),
      cellPreparedInfo: ref({}),
      calculateDisplayValueWithLinkFormat(cellTempData) {
        let { value, column } = cellTempData;
        let col = _.find(computedColumns.value, {
          dataField: column.dataField,
        });
        col = col?.optCol;
        if (col && col.dataFormat && col.dataFormat.FormatType) {
          let cellInfo = {
            value: value,
            valueText: value,
          };
          return publicMethod.customizeText(cellInfo, col);
        } else if (
          col &&
          (col.dataType == 'date' || col.dataType == 'datetime') &&
          col.format
        ) {
          const dateString = formatDate(value, col.format);
          return dateString;
        } else {
          return value;
        }
      },
      calculateDisplayValue(rowData, col) {
        let cellInfo = {
          value: rowData[col.dataField],
          valueText: rowData[col.dataField],
        };
        return publicMethod.customizeText(cellInfo, col);
      },
      calculateSortValue(rowData, col) {
        return rowData[col.dataField];
      },
      customizeText(cellInfo, col) {
        if (col.dataFormat && col.dataFormat.FormatType) {
          let formated = publicMethod.colFormat(cellInfo, col);
          return formated;
        }
        return cellInfo.valueText;
      },
      calculateFilterExpressionCol(
        value,
        selectedFilterOperations,
        target,
        col,
      ) {
        debugger;
        const column = publicMethod.widgetInstance.value.columnOption(
          col.dataField,
        );
        if (target === 'filterRow') {
          if (col && col.enumDisp && col.enumDisp.enumRanges) {
            return [
              `${col.dataField}_$mapping`,
              selectedFilterOperations,
              value,
            ];
          }
        }
        return column.defaultCalculateFilterExpression(
          value,
          selectedFilterOperations,
          target,
        );
      },
      calculateFilterExpressionDiscount(
        value,
        selectedFilterOperations,
        target,
        col,
      ) {
        debugger;
        const column = publicMethod.widgetInstance.value.columnOption(
          col.dataField,
        );
        if (Funcs.extractDiscount) {
          if (_.isArray(value)) {
            value = _.map(value, v =>
              v == null ? v : Funcs.extractDiscount(`${v}`),
            );
            value = value.reverse();
          } else {
            value = Funcs.extractDiscount(`${value}`);
          }
        }
        switch (selectedFilterOperations) {
          case '<':
            selectedFilterOperations = '>';
            break;
          case '<=':
            selectedFilterOperations = '>=';
            break;
          case '>':
            selectedFilterOperations = '<';
            break;
          case '>=':
            selectedFilterOperations = '<=';
            break;
        }
        return column.defaultCalculateFilterExpression(
          value,
          selectedFilterOperations,
          target,
        );
      },
      calculateFilterExpressionPercent(
        value,
        selectedFilterOperations,
        target,
        col,
      ) {
        const column = publicMethod.widgetInstance.value.columnOption(
          col.dataField,
        );

        if (_.isArray(value)) {
          value = _.map(value, v => v / 100);
        } else {
          value = value / 100;
        }

        return column.defaultCalculateFilterExpression(
          value,
          selectedFilterOperations,
          target,
        );
      },
      colFormat(cellInfo, col) {
        let formatFunc =
          FormatFunctions[col.dataFormat.FormatType] ||
          (cellInfo => cellInfo.valueText);
        return formatFunc(cellInfo, col);
      },
      optColumns2DxColumns(optCols) {
        return optCols.map(col => {
          let { dataField, caption, alignment, width, ValueInfo_caption } = col;
          if (ValueInfo_caption?.ReferenceExpr) {
            caption = t(ValueInfo_caption?.ReferenceExpr, caption);
          }
          let dataType = col.dataType?.toLowerCase();

          if (!width) {
            switch (dataType) {
              case 'date':
              case 'time':
              case 'datetime':
                width = '200px';
                break;
            }
          }
          if (width && false == isNaN(+width)) {
            width = width + 'px';
          }

          let extendCol = {
            name: col.dataField,
            dataField: col.dataField,
            caption: caption,
            width: width,
            visible: col.isShow,
            alignment: col.alignment,
            fixed: 'left' == col.fixedColumn || 'right' == col.fixedColumn,
            fixedPosition: col.fixedColumn,
            optCol: col,
          };

          if (extendCol.width === '') {
            if (props.isDev !== true) {
              delete extendCol.width;
            }
          }

          if (col.dataType == 'Date' || col.dataType == 'date') {
            // let dataCol = { ...col };
            if (props.isDev !== true) {
              extendCol.dataType = 'date';
              // col.format = "shortDate";
              extendCol.format = val => Funcs.DateToString(val);
            }
            // return extendCol;
          } else if (
            col.dataType == 'DateTime' ||
            col.dataType == 'Timestamp'
          ) {
            if (props.isDev !== true) {
              extendCol.dataType = 'datetime';
              // col.format = "shortDateShortTime";
              extendCol.format = val => Funcs.DateTimeToString(val);
            }
          } else if (col.dataType == 'Time' || col.dataType == 'time') {
            if (props.isDev !== true) {
              extendCol.dataType = 'datetime';
              // col.format = "longTime";
              extendCol.format = val => Funcs.DateTimeToTime(val);
            }
          } else if (
            col.dataType == 'Long' ||
            col.dataType == 'Int' ||
            col.dataType == 'Decimal'
          ) {
            if (props.isDev !== true) {
              extendCol.dataType = 'number';
              extendCol.format = '#0.############';
              extendCol.editorOptions = {
                format: extendCol.format,
                showClearButton: true,
              };
            }
          } else if (col.dataType == 'Boolean') {
            if (props.isDev !== true) {
              extendCol.dataType = 'boolean';
            }
          } else if (col.dataType == 'String') {
            if (props.isDev !== true) {
              extendCol.dataType = 'string';
            }
          } else {
            // return _.omit(col, ["dataType"]);
            if (props.isDev !== true) {
              delete extendCol.dataType;
            }
            // return extendCol;
          }

          return extendCol;
        });
      },
      dataSource: dataSource,
    };

    const readerLoading = () => {
      return (
        mappingProps.loading && (
          <QInnerLoading
            style={{
              zIndex: 110,
              color: 'var(--t-color)',
              opacity: '65%',
              width: treeListWidth.value,
            }}
            // style='z-index: 110;color: var(--t-color);  opacity: 65%;'
            showing
          />
        )
      );
    };

    const noDataText = computed(() => {
      return mappingProps.noDataText === '暂无数据'
        ? $q.lang.dataGrid?.emptyText
        : mappingProps.noDataText;
    });

    const readerNoDataPlaceholder = () => {
      return (
        dataSource.value.length === 0 && (
          <div
            style={{ width: treeListWidth.value || '100%' }}
            class={'no-data-placeholder-container'}
          >
            {/* {treeListWidth.value} */}
            <NoDataPlaceholder text={noDataText.value}></NoDataPlaceholder>
          </div>
        )
      );
    };

    watch(
      () => mappingProps?.optColumns,
      (newVal, oldVal) => {
        mappingProps.columns = publicMethod.optColumns2DxColumns(newVal);
      },
      // { immediate: true },
    );

    watch(
      () => mappingProps.loading,
      val => {
        // if (val) {
        //   publicMethod.widgetInstance.value?.beginUpdate();
        // } else {
        //   setTimeout(() => {
        //     publicMethod.widgetInstance.value?.endUpdate();
        //   }, 300);
        // }
        const $el = refTreeList.value._$element[0];
        treeListWidth.value = getComputedStyle($el)?.width;

        if (false === val) {
          nextTick(() => {
            emit('dataSourceLoaded');
          });
        }
      },
    );

    watch(
      () => mappingProps.showAutoFilterRow,
      () => {
        publicMethod.widgetInstance.value.clearFilter();
      },
    );

    Object.entries({
      ...publicMethod,
    }).forEach(([k, v], i, a) => {
      mappingExpose[k] = v;
    });

    const fixedColumns = computed(() => {
      return _.filter(mappingProps.optColumns, 'fixedColumn');
    });
    const groupFixedColumns = computed(() => {
      return _.groupBy(fixedColumns.value, 'fixedColumn');
    });

    const fixedColumnsWithLeft = computed(() => {
      return groupFixedColumns.value['left'] || [];
    });

    const hasFixedColumnsWithLeft = computed(() => {
      return fixedColumnsWithLeft.value.length > 0;
    });

    const fixedColumnsWithRight = computed(() => {
      return groupFixedColumns.value['right'] || [];
    });

    const hasFixedColumnsWithRight = computed(() => {
      return fixedColumnsWithRight.value.length > 0;
    });

    expose(mappingExpose);
    return () => {
      return (
        <div
          class={[
            'fas-dx-scope t-tree-list-container',
            hasFixedColumnsWithLeft.value &&
              't-tree-list-fixed-column-left-border',
            (mappingProps.enableCmdCol || hasFixedColumnsWithRight.value) &&
              't-tree-list-fixed-column-right-border',
          ]}
          v-show={mappingProps.visible}
          style={{
            '--t-treelist-dynamic-row-height': mappingProps.rowHeight,
          }}
        >
          {readerTreeList()}
          {readerLoading()}
          {readerNoDataPlaceholder()}
        </div>
      );
    };
  },
});
